﻿using System;
using Notoric.Commanding.CommandBase;

namespace Notoric.ViewModel.Elements.CWNotation
{
    /// <summary>
    /// Adapts a <see cref="Model.Elements.CWNotation.TimeSignature"/> isntance to a Windows Presentation Foundation View.
    /// </summary>
    public class TimeSignature : CoreSymbol
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="TimeSignature"/> class.
        /// </summary>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="Staff"/>
        /// </para>
        /// <para>
        /// The staff that directly owns this time signature.
        /// </para>
        /// </param>
        /// <param name="adaptedElement">
        /// <para>
        /// Type: <see cref="TimeSignature"/>
        /// </para>
        /// <para>
        /// The adapted element.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Any of the arguments is <see langword="null"/>.
        /// </exception>
        public TimeSignature(Staff owner, Model.Elements.CWNotation.TimeSignature adaptedElement)
            : base(owner, adaptedElement)
        {
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates an undoable command for setting the <see cref="Denominator"/> property.
        /// </summary>
        /// <param name="denominator">
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The denominator.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="UndoableCommandBase"/>
        /// </para>
        /// <para>
        /// The created command ready for execution.
        /// </para>
        /// </returns>
        public UndoableCommandBase CreateSetDenominatorCommand(ushort denominator)
        {
            return new SetterCommand<ushort>(this, "Denominator", denominator, UndoStack, RedoStack)
            {
                Name = "Change Time Signature"
            };
        }

        /// <summary>
        /// Creates an undoable command for setting the <see cref="Nominator"/> property.
        /// </summary>
        /// <param name="nominator">
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The denominator.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="UndoableCommandBase"/>
        /// </para>
        /// <para>
        /// The created command ready for execution.
        /// </para>
        /// </returns>
        public UndoableCommandBase CreateSetNominatorCommand(ushort nominator)
        {
            return new SetterCommand<ushort>(this, "Nominator", nominator, UndoStack, RedoStack)
            {
                Name = "Change Time Signature"
            };
        }

        /// <summary>
        /// Creates an undoable command for setting the <see cref="SignatureType"/> property.
        /// </summary>
        /// <param name="type">
        /// <para>
        /// Type: <see cref="TimeSignatureType"/>
        /// </para>
        /// <para>
        /// The type.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="UndoableCommandBase"/>
        /// </para>
        /// <para>
        /// The created command ready for execution.
        /// </para>
        /// </returns>
        public UndoableCommandBase CreateSetSignatureTypeCommand(TimeSignatureType type)
        {
            var modelType = (Model.Elements.TimeSignatureType)Enum.Parse(typeof(Model.Elements.TimeSignatureType), type.ToString());

            return new SetterCommand<Model.Elements.TimeSignatureType>(this, "SignatureType", modelType, UndoStack, RedoStack)
            {
                Name = "Change Time Signature"
            };
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the denominator of the time signature.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The denominator of the time signature.
        /// </para>
        /// </value>
        public ushort Denominator
        {
            get { return GetPropertyValue<ushort>("Denominator"); }
            set
            {
                if (UnsavedChanges.ContainsKey("Denominator"))
                {
                    var cmd = (SetterCommand<ushort>)UnsavedChanges["Denominator"];
                    cmd.Value = value;
                }
                else
                    UnsavedChanges["Denominator"] = CreateSetDenominatorCommand(value);

                RaisePropertyChanged("Denominator");
            }
        }

        /// <summary>
        /// Gets or sets the nominator of the time signature.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="UInt16"/>
        /// </para>
        /// <para>
        /// The nominator of the time signature.
        /// </para>
        /// </value>
        public ushort Nominator
        {
            get { return GetPropertyValue<ushort>("Nominator"); }
            set
            {
                if (UnsavedChanges.ContainsKey("Nominator"))
                {
                    var cmd = (SetterCommand<ushort>)UnsavedChanges["Nominator"];
                    cmd.Value = value;
                }
                else
                    UnsavedChanges["Nominator"] = CreateSetNominatorCommand(value);

                RaisePropertyChanged("Nominator");
            }
        }

        /// <summary>
        /// Gets or sets the type of the time signature.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="TimeSignatureType"/>
        /// </para>
        /// <para>
        /// The type of the time signature.
        /// </para>
        /// </value>
        public TimeSignatureType SignatureType
        {
            get { return (TimeSignatureType)Enum.Parse(typeof(TimeSignatureType), GetPropertyValue<Model.Elements.TimeSignatureType>("SignatureType").ToString()); }
            set
            {
                if (UnsavedChanges.ContainsKey("SignatureType"))
                {
                    var cmd = (SetterCommand<Model.Elements.TimeSignatureType>)UnsavedChanges["SignatureType"];
                    cmd.Value = (Model.Elements.TimeSignatureType)Enum.Parse(typeof(Model.Elements.TimeSignatureType), value.ToString());
                }
                else
                    UnsavedChanges["SignatureType"] = CreateSetSignatureTypeCommand(value);

                RaisePropertyChanged("SignatureType");
            }
        }

        #endregion

        #region ViewModelElement Members

        /// <inheritdoc/>
        public override string ElementNameKey
        {
            get { return elementNameKey; }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the dictionary key of a user-friendly name of this element.
        /// </summary>
        private const string elementNameKey = "ViewModel.ElementNames.TimeSignature";

        #endregion
    }
}
